/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * vim: set ts=8 sts=4 et sw=4 tw=99: * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */#include"jit/VMFunctions.h"#include"jsgc.h"#include"builtin/TypedObject.h"#include"frontend/BytecodeCompiler.h"#include"jit/arm/Simulator-arm.h"#include"jit/BaselineIC.h"#include"jit/JitCompartment.h"#include"jit/JitFrames.h"#include"jit/mips32/Simulator-mips32.h"#include"jit/mips64/Simulator-mips64.h"#include"vm/ArrayObject.h"#include"vm/Debugger.h"#include"vm/Interpreter.h"#include"vm/TraceLogging.h"#include"jit/BaselineFrame-inl.h"#include"jit/JitFrames-inl.h"#include"vm/Debugger-inl.h"#include"vm/Interpreter-inl.h"#include"vm/NativeObject-inl.h"#include"vm/StringObject-inl.h"#include"vm/TypeInference-inl.h"#include"vm/UnboxedObject-inl.h"usingnamespacejs;usingnamespacejs::jit;namespacejs{namespacejit{// Statics are initialized to null./* static */VMFunction*VMFunction::functions;AutoDetectInvalidation::AutoDetectInvalidation(JSContext*cx,MutableHandleValuerval):cx_(cx),ionScript_(GetTopJitJSScript(cx)->ionScript()),rval_(rval),disabled_(false){}voidVMFunction::addToFunctions(){this->next=functions;functions=this;}boolInvokeFunction(JSContext*cx,HandleObjectobj,boolconstructing,boolignoresReturnValue,uint32_targc,Value*argv,MutableHandleValuerval){TraceLoggerThread*logger=TraceLoggerForCurrentThread(cx);TraceLogStartEvent(logger,TraceLogger_Call);AutoArrayRooterargvRoot(cx,argc+1+constructing,argv);// Data in the argument vector is arranged for a JIT -> JIT call.RootedValuethisv(cx,argv[0]);Value*argvWithoutThis=argv+1;RootedValuefval(cx,ObjectValue(*obj));if(constructing){if(!IsConstructor(fval)){ReportValueError(cx,JSMSG_NOT_CONSTRUCTOR,JSDVG_IGNORE_STACK,fval,nullptr);returnfalse;}ConstructArgscargs(cx);if(!cargs.init(cx,argc))returnfalse;for(uint32_ti=0;i<argc;i++)cargs[i].set(argvWithoutThis[i]);RootedValuenewTarget(cx,argvWithoutThis[argc]);// If |this| hasn't been created, or is JS_UNINITIALIZED_LEXICAL,// we can use normal construction code without creating an extraneous// object.if(thisv.isMagic()){MOZ_ASSERT(thisv.whyMagic()==JS_IS_CONSTRUCTING||thisv.whyMagic()==JS_UNINITIALIZED_LEXICAL);RootedObjectobj(cx);if(!Construct(cx,fval,cargs,newTarget,&obj))returnfalse;rval.setObject(*obj);returntrue;}// Otherwise the default |this| has already been created. We could// almost perform a *call* at this point, but we'd break |new.target|// in the function. So in this one weird case we call a one-off// construction path that *won't* set |this| to JS_IS_CONSTRUCTING.returnInternalConstructWithProvidedThis(cx,fval,thisv,cargs,newTarget,rval);}InvokeArgsMaybeIgnoresReturnValueargs(cx,ignoresReturnValue);if(!args.init(cx,argc))returnfalse;for(size_ti=0;i<argc;i++)args[i].set(argvWithoutThis[i]);returnCall(cx,fval,thisv,args,rval);}boolInvokeFunctionShuffleNewTarget(JSContext*cx,HandleObjectobj,uint32_tnumActualArgs,uint32_tnumFormalArgs,Value*argv,MutableHandleValuerval){MOZ_ASSERT(numFormalArgs>numActualArgs);argv[1+numActualArgs]=argv[1+numFormalArgs];returnInvokeFunction(cx,obj,true,false,numActualArgs,argv,rval);}#ifdef JS_SIMULATORstaticboolCheckSimulatorRecursionLimitWithExtra(JSContext*cx,uint32_textra){if(cx->simulator()->overRecursedWithExtra(extra)){ReportOverRecursed(cx);returnfalse;}returntrue;}#endifboolCheckOverRecursed(JSContext*cx){// We just failed the jitStackLimit check. There are two possible reasons:// - jitStackLimit was the real stack limit and we're over-recursed// - jitStackLimit was set to UINTPTR_MAX by JSRuntime::requestInterrupt// and we need to call JSRuntime::handleInterrupt.#ifdef JS_SIMULATORif(!CheckSimulatorRecursionLimitWithExtra(cx,0))returnfalse;#elseif(!CheckRecursionLimit(cx))returnfalse;#endifgc::MaybeVerifyBarriers(cx);returncx->handleInterrupt();}// This function can get called in two contexts. In the usual context, it's// called with earlyCheck=false, after the env chain has been initialized on// a baseline frame. In this case, it's ok to throw an exception, so a failed// stack check returns false, and a successful stack check promps a check for// an interrupt from the runtime, which may also cause a false return.//// In the second case, it's called with earlyCheck=true, prior to frame// initialization. An exception cannot be thrown in this instance, so instead// an error flag is set on the frame and true returned.boolCheckOverRecursedWithExtra(JSContext*cx,BaselineFrame*frame,uint32_textra,uint32_tearlyCheck){MOZ_ASSERT_IF(earlyCheck,!frame->overRecursed());// See |CheckOverRecursed| above. This is a variant of that function which// accepts an argument holding the extra stack space needed for the Baseline// frame that's about to be pushed.uint8_tspDummy;uint8_t*checkSp=(&spDummy)-extra;if(earlyCheck){#ifdef JS_SIMULATOR(void)checkSp;if(!CheckSimulatorRecursionLimitWithExtra(cx,extra))frame->setOverRecursed();#elseif(!CheckRecursionLimitWithStackPointer(cx,checkSp))frame->setOverRecursed();#endifreturntrue;}// The OVERRECURSED flag may have already been set on the frame by an// early over-recursed check. If so, throw immediately.if(frame->overRecursed())returnfalse;#ifdef JS_SIMULATORif(!CheckSimulatorRecursionLimitWithExtra(cx,extra))returnfalse;#elseif(!CheckRecursionLimitWithStackPointer(cx,checkSp))returnfalse;#endifgc::MaybeVerifyBarriers(cx);returncx->handleInterrupt();}JSObject*BindVar(JSContext*cx,HandleObjectenvChain){JSObject*obj=envChain;while(!obj->isQualifiedVarObj())obj=obj->enclosingEnvironment();MOZ_ASSERT(obj);returnobj;}boolDefVar(JSContext*cx,HandlePropertyNamedn,unsignedattrs,HandleObjectenvChain){// Given the ScopeChain, extract the VarObj.RootedObjectobj(cx,BindVar(cx,envChain));returnDefVarOperation(cx,obj,dn,attrs);}boolDefLexical(JSContext*cx,HandlePropertyNamedn,unsignedattrs,HandleObjectenvChain){// Find the extensible lexical scope.Rooted<LexicalEnvironmentObject*>lexicalEnv(cx,&NearestEnclosingExtensibleLexicalEnvironment(envChain));// Find the variables object.RootedObjectvarObj(cx,BindVar(cx,envChain));returnDefLexicalOperation(cx,lexicalEnv,varObj,dn,attrs);}boolDefGlobalLexical(JSContext*cx,HandlePropertyNamedn,unsignedattrs){Rooted<LexicalEnvironmentObject*>globalLexical(cx,&cx->global()->lexicalEnvironment());returnDefLexicalOperation(cx,globalLexical,cx->global(),dn,attrs);}boolMutatePrototype(JSContext*cx,HandlePlainObjectobj,HandleValuevalue){if(!value.isObjectOrNull())returntrue;RootedObjectnewProto(cx,value.toObjectOrNull());returnSetPrototype(cx,obj,newProto);}boolInitProp(JSContext*cx,HandleObjectobj,HandlePropertyNamename,HandleValuevalue,jsbytecode*pc){RootedIdid(cx,NameToId(name));returnInitPropertyOperation(cx,JSOp(*pc),obj,id,value);}template<boolEqual>boolLooselyEqual(JSContext*cx,MutableHandleValuelhs,MutableHandleValuerhs,bool*res){if(!js::LooselyEqual(cx,lhs,rhs,res))returnfalse;if(!Equal)*res=!*res;returntrue;}templateboolLooselyEqual<true>(JSContext*cx,MutableHandleValuelhs,MutableHandleValuerhs,bool*res);templateboolLooselyEqual<false>(JSContext*cx,MutableHandleValuelhs,MutableHandleValuerhs,bool*res);template<boolEqual>boolStrictlyEqual(JSContext*cx,MutableHandleValuelhs,MutableHandleValuerhs,bool*res){if(!js::StrictlyEqual(cx,lhs,rhs,res))returnfalse;if(!Equal)*res=!*res;returntrue;}templateboolStrictlyEqual<true>(JSContext*cx,MutableHandleValuelhs,MutableHandleValuerhs,bool*res);templateboolStrictlyEqual<false>(JSContext*cx,MutableHandleValuelhs,MutableHandleValuerhs,bool*res);boolLessThan(JSContext*cx,MutableHandleValuelhs,MutableHandleValuerhs,bool*res){returnLessThanOperation(cx,lhs,rhs,res);}boolLessThanOrEqual(JSContext*cx,MutableHandleValuelhs,MutableHandleValuerhs,bool*res){returnLessThanOrEqualOperation(cx,lhs,rhs,res);}boolGreaterThan(JSContext*cx,MutableHandleValuelhs,MutableHandleValuerhs,bool*res){returnGreaterThanOperation(cx,lhs,rhs,res);}boolGreaterThanOrEqual(JSContext*cx,MutableHandleValuelhs,MutableHandleValuerhs,bool*res){returnGreaterThanOrEqualOperation(cx,lhs,rhs,res);}template<boolEqual>boolStringsEqual(JSContext*cx,HandleStringlhs,HandleStringrhs,bool*res){if(!js::EqualStrings(cx,lhs,rhs,res))returnfalse;if(!Equal)*res=!*res;returntrue;}templateboolStringsEqual<true>(JSContext*cx,HandleStringlhs,HandleStringrhs,bool*res);templateboolStringsEqual<false>(JSContext*cx,HandleStringlhs,HandleStringrhs,bool*res);boolStringSplitHelper(JSContext*cx,HandleStringstr,HandleStringsep,HandleObjectGroupgroup,uint32_tlimit,MutableHandleValueresult){JSObject*resultObj=str_split_string(cx,group,str,sep,limit);if(!resultObj)returnfalse;result.setObject(*resultObj);returntrue;}boolArrayPopDense(JSContext*cx,HandleObjectobj,MutableHandleValuerval){MOZ_ASSERT(obj->is<ArrayObject>()||obj->is<UnboxedArrayObject>());AutoDetectInvalidationadi(cx,rval);JS::AutoValueArray<2>argv(cx);argv[0].setUndefined();argv[1].setObject(*obj);if(!js::array_pop(cx,0,argv.begin()))returnfalse;// If the result is |undefined|, the array was probably empty and we// have to monitor the return value.rval.set(argv[0]);if(rval.isUndefined())TypeScript::Monitor(cx,rval);returntrue;}boolArrayPushDense(JSContext*cx,HandleObjectobj,HandleValuev,uint32_t*length){*length=GetAnyBoxedOrUnboxedArrayLength(obj);DenseElementResultresult=SetOrExtendAnyBoxedOrUnboxedDenseElements(cx,obj,*length,v.address(),1,ShouldUpdateTypes::DontUpdate);if(result!=DenseElementResult::Incomplete){(*length)++;returnresult==DenseElementResult::Success;}// AutoDetectInvalidation uses GetTopJitJSScript(cx)->ionScript(), but it's// possible the SetOrExtendAnyBoxedOrUnboxedDenseElements call already// invalidated the IonScript. JitFrameIterator::ionScript works when the// script is invalidated so we use that instead.JitFrameIteratorit(cx);MOZ_ASSERT(it.type()==JitFrame_Exit);++it;IonScript*ionScript=it.ionScript();JS::AutoValueArray<3>argv(cx);AutoDetectInvalidationadi(cx,argv[0],ionScript);argv[0].setUndefined();argv[1].setObject(*obj);argv[2].set(v);if(!js::array_push(cx,1,argv.begin()))returnfalse;if(argv[0].isInt32()){*length=argv[0].toInt32();returntrue;}// array_push changed the length to be larger than INT32_MAX. In this case// OBJECT_FLAG_LENGTH_OVERFLOW was set, TI invalidated the script, and the// AutoDetectInvalidation instance on the stack will replace *length with// the actual return value during bailout.MOZ_ASSERT(adi.shouldSetReturnOverride());MOZ_ASSERT(argv[0].toDouble()==double(INT32_MAX)+1);*length=0;returntrue;}boolArrayShiftDense(JSContext*cx,HandleObjectobj,MutableHandleValuerval){MOZ_ASSERT(obj->is<ArrayObject>()||obj->is<UnboxedArrayObject>());AutoDetectInvalidationadi(cx,rval);JS::AutoValueArray<2>argv(cx);argv[0].setUndefined();argv[1].setObject(*obj);if(!js::array_shift(cx,0,argv.begin()))returnfalse;// If the result is |undefined|, the array was probably empty and we// have to monitor the return value.rval.set(argv[0]);if(rval.isUndefined())TypeScript::Monitor(cx,rval);returntrue;}JSString*ArrayJoin(JSContext*cx,HandleObjectarray,HandleStringsep){JS::AutoValueArray<3>argv(cx);argv[0].setUndefined();argv[1].setObject(*array);argv[2].setString(sep);if(!js::array_join(cx,1,argv.begin()))returnnullptr;returnargv[0].toString();}boolSetArrayLength(JSContext*cx,HandleObjectobj,HandleValuevalue,boolstrict){Handle<ArrayObject*>array=obj.as<ArrayObject>();RootedIdid(cx,NameToId(cx->names().length));ObjectOpResultresult;// SetArrayLength is called by IC stubs for SetProp and SetElem on arrays'// "length" property.//// ArraySetLength below coerces |value| before checking for length being// writable, and in the case of illegal values, will throw RangeError even// when "length" is not writable. This is incorrect observable behavior,// as a regular [[Set]] operation will check for "length" being// writable before attempting any assignment.//// So, perform ArraySetLength if and only if "length" is writable.if(array->lengthIsWritable()){if(!ArraySetLength(cx,array,id,JSPROP_PERMANENT,value,result))returnfalse;}else{MOZ_ALWAYS_TRUE(result.fail(JSMSG_READ_ONLY));}returnresult.checkStrictErrorOrWarning(cx,obj,id,strict);}boolCharCodeAt(JSContext*cx,HandleStringstr,int32_tindex,uint32_t*code){char16_tc;if(!str->getChar(cx,index,&c))returnfalse;*code=c;returntrue;}JSFlatString*StringFromCharCode(JSContext*cx,int32_tcode){char16_tc=char16_t(code);if(StaticStrings::hasUnit(c))returncx->staticStrings().getUnit(c);returnNewStringCopyN<CanGC>(cx,&c,1);}JSString*StringFromCodePoint(JSContext*cx,int32_tcodePoint){RootedValuerval(cx,Int32Value(codePoint));if(!str_fromCodePoint_one_arg(cx,rval,&rval))returnnullptr;returnrval.toString();}boolSetProperty(JSContext*cx,HandleObjectobj,HandlePropertyNamename,HandleValuevalue,boolstrict,jsbytecode*pc){RootedIdid(cx,NameToId(name));JSOpop=JSOp(*pc);if(op==JSOP_SETALIASEDVAR||op==JSOP_INITALIASEDLEXICAL){// Aliased var assigns ignore readonly attributes on the property, as// required for initializing 'const' closure variables.Shape*shape=obj->as<NativeObject>().lookup(cx,name);MOZ_ASSERT(shape&&shape->hasSlot());obj->as<NativeObject>().setSlotWithType(cx,shape,value);returntrue;}RootedValuereceiver(cx,ObjectValue(*obj));ObjectOpResultresult;if(MOZ_LIKELY(!obj->getOpsSetProperty())){if(!NativeSetProperty(cx,obj.as<NativeObject>(),id,value,receiver,(op==JSOP_SETNAME||op==JSOP_STRICTSETNAME||op==JSOP_SETGNAME||op==JSOP_STRICTSETGNAME)?Unqualified:Qualified,result)){returnfalse;}}else{if(!SetProperty(cx,obj,id,value,receiver,result))returnfalse;}returnresult.checkStrictErrorOrWarning(cx,obj,id,strict);}boolInterruptCheck(JSContext*cx){gc::MaybeVerifyBarriers(cx);{JSRuntime*rt=cx->runtime();JitRuntime::AutoPreventBackedgePatchingapbp(rt);cx->zone()->group()->jitZoneGroup->patchIonBackedges(cx,JitZoneGroup::BackedgeLoopHeader);}returnCheckForInterrupt(cx);}void*MallocWrapper(JSRuntime*rt,size_tnbytes){returnrt->pod_malloc<uint8_t>(nbytes);}JSObject*NewCallObject(JSContext*cx,HandleShapeshape,HandleObjectGroupgroup){JSObject*obj=CallObject::create(cx,shape,group);if(!obj)returnnullptr;// The JIT creates call objects in the nursery, so elides barriers for// the initializing writes. The interpreter, however, may have allocated// the call object tenured, so barrier as needed before re-entering.if(!IsInsideNursery(obj))cx->zone()->group()->storeBuffer().putWholeCell(obj);returnobj;}JSObject*NewSingletonCallObject(JSContext*cx,HandleShapeshape){JSObject*obj=CallObject::createSingleton(cx,shape);if(!obj)returnnullptr;// The JIT creates call objects in the nursery, so elides barriers for// the initializing writes. The interpreter, however, may have allocated// the call object tenured, so barrier as needed before re-entering.MOZ_ASSERT(!IsInsideNursery(obj),"singletons are created in the tenured heap");cx->zone()->group()->storeBuffer().putWholeCell(obj);returnobj;}JSObject*NewStringObject(JSContext*cx,HandleStringstr){returnStringObject::create(cx,str);}boolOperatorIn(JSContext*cx,HandleValuekey,HandleObjectobj,bool*out){RootedIdid(cx);returnToPropertyKey(cx,key,&id)&&HasProperty(cx,obj,id,out);}boolOperatorInI(JSContext*cx,uint32_tindex,HandleObjectobj,bool*out){RootedValuekey(cx,Int32Value(index));returnOperatorIn(cx,key,obj,out);}boolGetIntrinsicValue(JSContext*cx,HandlePropertyNamename,MutableHandleValuerval){if(!GlobalObject::getIntrinsicValue(cx,cx->global(),name,rval))returnfalse;// This function is called when we try to compile a cold getintrinsic// op. MCallGetIntrinsicValue has an AliasSet of None for optimization// purposes, as its side effect is not observable from JS. We are// guaranteed to bail out after this function, but because of its AliasSet,// type info will not be reflowed. Manually monitor here.TypeScript::Monitor(cx,rval);returntrue;}boolCreateThis(JSContext*cx,HandleObjectcallee,HandleObjectnewTarget,MutableHandleValuerval){rval.set(MagicValue(JS_IS_CONSTRUCTING));if(callee->is<JSFunction>()){RootedFunctionfun(cx,&callee->as<JSFunction>());if(fun->isInterpreted()&&fun->isConstructor()){JSScript*script=JSFunction::getOrCreateScript(cx,fun);if(!script||!script->ensureHasTypes(cx))returnfalse;if(fun->isBoundFunction()||script->isDerivedClassConstructor()){rval.set(MagicValue(JS_UNINITIALIZED_LEXICAL));}else{JSObject*thisObj=CreateThisForFunction(cx,callee,newTarget,GenericObject);if(!thisObj)returnfalse;rval.set(ObjectValue(*thisObj));}}}returntrue;}voidGetDynamicName(JSContext*cx,JSObject*envChain,JSString*str,Value*vp){// Lookup a string on the env chain, returning either the value found or// undefined through rval. This function is infallible, and cannot GC or// invalidate.JSAtom*atom;if(str->isAtom()){atom=&str->asAtom();}else{atom=AtomizeString(cx,str);if(!atom){vp->setUndefined();return;}}if(!frontend::IsIdentifier(atom)||frontend::IsKeyword(atom)){vp->setUndefined();return;}PropertyResultprop;JSObject*scope=nullptr;JSObject*pobj=nullptr;if(LookupNameNoGC(cx,atom->asPropertyName(),envChain,&scope,&pobj,&prop)){if(FetchNameNoGC(pobj,prop,MutableHandleValue::fromMarkedLocation(vp)))return;}vp->setUndefined();}voidPostWriteBarrier(JSRuntime*rt,JSObject*obj){JS::AutoCheckCannotGCnogc;MOZ_ASSERT(!IsInsideNursery(obj));rt->gc.storeBuffer().putWholeCell(obj);}staticconstsize_tMAX_WHOLE_CELL_BUFFER_SIZE=4096;template<IndexInBoundsInBounds>voidPostWriteElementBarrier(JSRuntime*rt,JSObject*obj,int32_tindex){JS::AutoCheckCannotGCnogc;MOZ_ASSERT(!IsInsideNursery(obj));if(InBounds==IndexInBounds::Yes){MOZ_ASSERT(uint32_t(index)<obj->as<NativeObject>().getDenseInitializedLength());}else{if(MOZ_UNLIKELY(!obj->is<NativeObject>())||uint32_t(index)>=obj->as<NativeObject>().getDenseInitializedLength()){rt->gc.storeBuffer().putWholeCell(obj);return;}}NativeObject*nobj=&obj->as<NativeObject>();if(nobj->isInWholeCellBuffer())return;if(nobj->getDenseInitializedLength()>MAX_WHOLE_CELL_BUFFER_SIZE#ifdef JS_GC_ZEAL||rt->hasZealMode(gc::ZealMode::ElementsBarrier)#endif){rt->gc.storeBuffer().putSlot(nobj,HeapSlot::Element,nobj->unshiftedIndex(index),1);return;}rt->gc.storeBuffer().putWholeCell(obj);}templatevoidPostWriteElementBarrier<IndexInBounds::Yes>(JSRuntime*rt,JSObject*obj,int32_tindex);templatevoidPostWriteElementBarrier<IndexInBounds::Maybe>(JSRuntime*rt,JSObject*obj,int32_tindex);voidPostGlobalWriteBarrier(JSRuntime*rt,JSObject*obj){MOZ_ASSERT(obj->is<GlobalObject>());if(!obj->compartment()->globalWriteBarriered){PostWriteBarrier(rt,obj);obj->compartment()->globalWriteBarriered=1;}}int32_tGetIndexFromString(JSString*str){// We shouldn't GC here as this is called directly from IC code.JS::AutoCheckCannotGCnogc;if(!str->isFlat())return-1;uint32_tindex;if(!str->asFlat().isIndex(&index)||index>INT32_MAX)return-1;returnint32_t(index);}JSObject*WrapObjectPure(JSContext*cx,JSObject*obj){// IC code calls this directly so we shouldn't GC.JS::AutoCheckCannotGCnogc;MOZ_ASSERT(obj);MOZ_ASSERT(cx->compartment()!=obj->compartment());// From: JSCompartment::getNonWrapperObjectForCurrentCompartment// Note that if the object is same-compartment, but has been wrapped into a// different compartment, we need to unwrap it and return the bare same-// compartment object. Note again that windows are always wrapped by a// WindowProxy even when same-compartment so take care not to strip this// particular wrapper.obj=UncheckedUnwrap(obj,/* stopAtWindowProxy = */true);if(cx->compartment()==obj->compartment()){MOZ_ASSERT(!IsWindow(obj));JS::ExposeObjectToActiveJS(obj);returnobj;}// Try to Lookup an existing wrapper for this object. We assume that// if we can find such a wrapper, not calling preWrap is correct.if(WrapperMap::Ptrp=cx->compartment()->lookupWrapper(obj)){JSObject*wrapped=&p->value().get().toObject();// Ensure the wrapper is still exposed.JS::ExposeObjectToActiveJS(wrapped);returnwrapped;}returnnullptr;}boolDebugPrologue(JSContext*cx,BaselineFrame*frame,jsbytecode*pc,bool*mustReturn){*mustReturn=false;switch(Debugger::onEnterFrame(cx,frame)){caseJSTRAP_CONTINUE:returntrue;caseJSTRAP_RETURN:// The script is going to return immediately, so we have to call the// debug epilogue handler as well.MOZ_ASSERT(frame->hasReturnValue());*mustReturn=true;returnjit::DebugEpilogue(cx,frame,pc,true);caseJSTRAP_THROW:caseJSTRAP_ERROR:returnfalse;default:MOZ_CRASH("bad Debugger::onEnterFrame status");}}boolDebugEpilogueOnBaselineReturn(JSContext*cx,BaselineFrame*frame,jsbytecode*pc){if(!DebugEpilogue(cx,frame,pc,true)){// DebugEpilogue popped the frame by updating exitFP, so run the stop// event here before we enter the exception handler.TraceLoggerThread*logger=TraceLoggerForCurrentThread(cx);TraceLogStopEvent(logger,TraceLogger_Baseline);TraceLogStopEvent(logger,TraceLogger_Scripts);returnfalse;}returntrue;}boolDebugEpilogue(JSContext*cx,BaselineFrame*frame,jsbytecode*pc,boolok){// If Debugger::onLeaveFrame returns |true| we have to return the frame's// return value. If it returns |false|, the debugger threw an exception.// In both cases we have to pop debug scopes.ok=Debugger::onLeaveFrame(cx,frame,pc,ok);// Unwind to the outermost environment and set pc to the end of the// script, regardless of error.EnvironmentIterei(cx,frame,pc);UnwindAllEnvironmentsInFrame(cx,ei);JSScript*script=frame->script();frame->setOverridePc(script->lastPC());if(!ok){// Pop this frame by updating exitFP, so that the exception handling// code will start at the previous frame.JitFrameLayout*prefix=frame->framePrefix();EnsureBareExitFrame(cx,prefix);returnfalse;}// Clear the override pc. This is not necessary for correctness: the frame// will return immediately, but this simplifies the check we emit in debug// builds after each callVM, to ensure this flag is not set.frame->clearOverridePc();returntrue;}voidFrameIsDebuggeeCheck(BaselineFrame*frame){if(frame->script()->isDebuggee())frame->setIsDebuggee();}JSObject*CreateGenerator(JSContext*cx,BaselineFrame*frame){returnGeneratorObject::create(cx,frame);}boolNormalSuspend(JSContext*cx,HandleObjectobj,BaselineFrame*frame,jsbytecode*pc,uint32_tstackDepth){MOZ_ASSERT(*pc==JSOP_YIELD||*pc==JSOP_AWAIT);// Return value is still on the stack.MOZ_ASSERT(stackDepth>=1);// The expression stack slots are stored on the stack in reverse order, so// we copy them to a Vector and pass a pointer to that instead. We use// stackDepth - 1 because we don't want to include the return value.AutoValueVectorexprStack(cx);if(!exprStack.reserve(stackDepth-1))returnfalse;size_tfirstSlot=frame->numValueSlots()-stackDepth;for(size_ti=0;i<stackDepth-1;i++)exprStack.infallibleAppend(*frame->valueSlot(firstSlot+i));MOZ_ASSERT(exprStack.length()==stackDepth-1);returnGeneratorObject::normalSuspend(cx,obj,frame,pc,exprStack.begin(),stackDepth-1);}boolFinalSuspend(JSContext*cx,HandleObjectobj,BaselineFrame*frame,jsbytecode*pc){MOZ_ASSERT(*pc==JSOP_FINALYIELDRVAL);if(!GeneratorObject::finalSuspend(cx,obj)){TraceLoggerThread*logger=TraceLoggerForCurrentThread(cx);TraceLogStopEvent(logger,TraceLogger_Engine);TraceLogStopEvent(logger,TraceLogger_Scripts);// Leave this frame and propagate the exception to the caller.returnDebugEpilogue(cx,frame,pc,/* ok = */false);}returntrue;}boolInterpretResume(JSContext*cx,HandleObjectobj,HandleValueval,HandlePropertyNamekind,MutableHandleValuerval){MOZ_ASSERT(obj->is<GeneratorObject>());RootedValueselfHostedFun(cx);if(!GlobalObject::getIntrinsicValue(cx,cx->global(),cx->names().InterpretGeneratorResume,&selfHostedFun)){returnfalse;}MOZ_ASSERT(selfHostedFun.toObject().is<JSFunction>());FixedInvokeArgs<3>args(cx);args[0].setObject(*obj);args[1].set(val);args[2].setString(kind);returnCall(cx,selfHostedFun,UndefinedHandleValue,args,rval);}boolDebugAfterYield(JSContext*cx,BaselineFrame*frame){// The BaselineFrame has just been constructed by JSOP_RESUME in the// caller. We need to set its debuggee flag as necessary.if(frame->script()->isDebuggee())frame->setIsDebuggee();returntrue;}boolGeneratorThrowOrClose(JSContext*cx,BaselineFrame*frame,Handle<GeneratorObject*>genObj,HandleValuearg,uint32_tresumeKind){// Set the frame's pc to the current resume pc, so that frame iterators// work. This function always returns false, so we're guaranteed to enter// the exception handler where we will clear the pc.JSScript*script=frame->script();uint32_toffset=script->yieldAndAwaitOffsets()[genObj->yieldAndAwaitIndex()];frame->setOverridePc(script->offsetToPC(offset));MOZ_ALWAYS_TRUE(DebugAfterYield(cx,frame));MOZ_ALWAYS_FALSE(js::GeneratorThrowOrClose(cx,frame,genObj,arg,resumeKind));returnfalse;}boolCheckGlobalOrEvalDeclarationConflicts(JSContext*cx,BaselineFrame*frame){RootedScriptscript(cx,frame->script());RootedObjectenvChain(cx,frame->environmentChain());RootedObjectvarObj(cx,BindVar(cx,envChain));if(script->isForEval()){// Strict eval and eval in parameter default expressions have their// own call objects.//// Non-strict eval may introduce 'var' bindings that conflict with// lexical bindings in an enclosing lexical scope.if(!script->bodyScope()->hasEnvironment()){MOZ_ASSERT(!script->strict()&&(!script->enclosingScope()->is<FunctionScope>()||!script->enclosingScope()->as<FunctionScope>().hasParameterExprs()));if(!CheckEvalDeclarationConflicts(cx,script,envChain,varObj))returnfalse;}}else{Rooted<LexicalEnvironmentObject*>lexicalEnv(cx,&NearestEnclosingExtensibleLexicalEnvironment(envChain));if(!CheckGlobalDeclarationConflicts(cx,script,lexicalEnv,varObj))returnfalse;}returntrue;}boolGlobalNameConflictsCheckFromIon(JSContext*cx,HandleScriptscript){Rooted<LexicalEnvironmentObject*>globalLexical(cx,&cx->global()->lexicalEnvironment());returnCheckGlobalDeclarationConflicts(cx,script,globalLexical,cx->global());}boolInitFunctionEnvironmentObjects(JSContext*cx,BaselineFrame*frame){returnframe->initFunctionEnvironmentObjects(cx);}boolNewArgumentsObject(JSContext*cx,BaselineFrame*frame,MutableHandleValueres){ArgumentsObject*obj=ArgumentsObject::createExpected(cx,frame);if(!obj)returnfalse;res.setObject(*obj);returntrue;}JSObject*CopyLexicalEnvironmentObject(JSContext*cx,HandleObjectenv,boolcopySlots){Handle<LexicalEnvironmentObject*>lexicalEnv=env.as<LexicalEnvironmentObject>();if(copySlots)returnLexicalEnvironmentObject::clone(cx,lexicalEnv);returnLexicalEnvironmentObject::recreate(cx,lexicalEnv);}JSObject*InitRestParameter(JSContext*cx,uint32_tlength,Value*rest,HandleObjecttemplateObj,HandleObjectobjRes){if(objRes){Rooted<ArrayObject*>arrRes(cx,&objRes->as<ArrayObject>());MOZ_ASSERT(!arrRes->getDenseInitializedLength());MOZ_ASSERT(arrRes->group()==templateObj->group());// Fast path: we managed to allocate the array inline; initialize the// slots.if(length>0){if(!arrRes->ensureElements(cx,length))returnnullptr;arrRes->setDenseInitializedLength(length);arrRes->initDenseElements(0,rest,length);arrRes->setLengthInt32(length);}returnarrRes;}NewObjectKindnewKind=templateObj->group()->shouldPreTenure()?TenuredObject:GenericObject;ArrayObject*arrRes=NewDenseCopiedArray(cx,length,rest,nullptr,newKind);if(arrRes)arrRes->setGroup(templateObj->group());returnarrRes;}boolHandleDebugTrap(JSContext*cx,BaselineFrame*frame,uint8_t*retAddr,bool*mustReturn){*mustReturn=false;RootedScriptscript(cx,frame->script());jsbytecode*pc=script->baselineScript()->icEntryFromReturnAddress(retAddr).pc(script);if(*pc==JSOP_DEBUGAFTERYIELD){// JSOP_DEBUGAFTERYIELD will set the frame's debuggee flag, but if we// set a breakpoint there we have to do it now.MOZ_ASSERT(!frame->isDebuggee());if(!DebugAfterYield(cx,frame))returnfalse;}MOZ_ASSERT(frame->isDebuggee());MOZ_ASSERT(script->stepModeEnabled()||script->hasBreakpointsAt(pc));RootedValuerval(cx);JSTrapStatusstatus=JSTRAP_CONTINUE;if(script->stepModeEnabled())status=Debugger::onSingleStep(cx,&rval);if(status==JSTRAP_CONTINUE&&script->hasBreakpointsAt(pc))status=Debugger::onTrap(cx,&rval);switch(status){caseJSTRAP_CONTINUE:break;caseJSTRAP_ERROR:returnfalse;caseJSTRAP_RETURN:*mustReturn=true;frame->setReturnValue(rval);returnjit::DebugEpilogue(cx,frame,pc,true);caseJSTRAP_THROW:cx->setPendingException(rval);returnfalse;default:MOZ_CRASH("Invalid trap status");}returntrue;}boolOnDebuggerStatement(JSContext*cx,BaselineFrame*frame,jsbytecode*pc,bool*mustReturn){*mustReturn=false;switch(Debugger::onDebuggerStatement(cx,frame)){caseJSTRAP_ERROR:returnfalse;caseJSTRAP_CONTINUE:returntrue;caseJSTRAP_RETURN:*mustReturn=true;returnjit::DebugEpilogue(cx,frame,pc,true);caseJSTRAP_THROW:returnfalse;default:MOZ_CRASH("Invalid trap status");}}boolGlobalHasLiveOnDebuggerStatement(JSContext*cx){returncx->compartment()->isDebuggee()&&Debugger::hasLiveHook(cx->global(),Debugger::OnDebuggerStatement);}boolPushLexicalEnv(JSContext*cx,BaselineFrame*frame,Handle<LexicalScope*>scope){returnframe->pushLexicalEnvironment(cx,scope);}boolPopLexicalEnv(JSContext*cx,BaselineFrame*frame){frame->popOffEnvironmentChain<LexicalEnvironmentObject>();returntrue;}boolDebugLeaveThenPopLexicalEnv(JSContext*cx,BaselineFrame*frame,jsbytecode*pc){MOZ_ALWAYS_TRUE(DebugLeaveLexicalEnv(cx,frame,pc));frame->popOffEnvironmentChain<LexicalEnvironmentObject>();returntrue;}boolFreshenLexicalEnv(JSContext*cx,BaselineFrame*frame){returnframe->freshenLexicalEnvironment(cx);}boolDebugLeaveThenFreshenLexicalEnv(JSContext*cx,BaselineFrame*frame,jsbytecode*pc){MOZ_ALWAYS_TRUE(DebugLeaveLexicalEnv(cx,frame,pc));returnframe->freshenLexicalEnvironment(cx);}boolRecreateLexicalEnv(JSContext*cx,BaselineFrame*frame){returnframe->recreateLexicalEnvironment(cx);}boolDebugLeaveThenRecreateLexicalEnv(JSContext*cx,BaselineFrame*frame,jsbytecode*pc){MOZ_ALWAYS_TRUE(DebugLeaveLexicalEnv(cx,frame,pc));returnframe->recreateLexicalEnvironment(cx);}boolDebugLeaveLexicalEnv(JSContext*cx,BaselineFrame*frame,jsbytecode*pc){MOZ_ASSERT(frame->script()->baselineScript()->hasDebugInstrumentation());if(cx->compartment()->isDebuggee())DebugEnvironments::onPopLexical(cx,frame,pc);returntrue;}boolPushVarEnv(JSContext*cx,BaselineFrame*frame,HandleScopescope){returnframe->pushVarEnvironment(cx,scope);}boolPopVarEnv(JSContext*cx,BaselineFrame*frame){frame->popOffEnvironmentChain<VarEnvironmentObject>();returntrue;}boolEnterWith(JSContext*cx,BaselineFrame*frame,HandleValueval,Handle<WithScope*>templ){returnEnterWithOperation(cx,frame,val,templ);}boolLeaveWith(JSContext*cx,BaselineFrame*frame){if(MOZ_UNLIKELY(frame->isDebuggee()))DebugEnvironments::onPopWith(frame);frame->popOffEnvironmentChain<WithEnvironmentObject>();returntrue;}boolInitBaselineFrameForOsr(BaselineFrame*frame,InterpreterFrame*interpFrame,uint32_tnumStackValues){returnframe->initForOsr(interpFrame,numStackValues);}JSObject*CreateDerivedTypedObj(JSContext*cx,HandleObjectdescr,HandleObjectowner,int32_toffset){MOZ_ASSERT(descr->is<TypeDescr>());MOZ_ASSERT(owner->is<TypedObject>());Rooted<TypeDescr*>descr1(cx,&descr->as<TypeDescr>());Rooted<TypedObject*>owner1(cx,&owner->as<TypedObject>());returnOutlineTypedObject::createDerived(cx,descr1,owner1,offset);}JSString*StringReplace(JSContext*cx,HandleStringstring,HandleStringpattern,HandleStringrepl){MOZ_ASSERT(string);MOZ_ASSERT(pattern);MOZ_ASSERT(repl);returnstr_replace_string_raw(cx,string,pattern,repl);}boolRecompileImpl(JSContext*cx,boolforce){MOZ_ASSERT(cx->currentlyRunningInJit());JitActivationIteratoractivations(cx);JitFrameIteratoriter(activations);MOZ_ASSERT(iter.type()==JitFrame_Exit);++iter;RootedScriptscript(cx,iter.script());MOZ_ASSERT(script->hasIonScript());if(!IsIonEnabled(cx))returntrue;MethodStatusstatus=Recompile(cx,script,nullptr,nullptr,force);if(status==Method_Error)returnfalse;returntrue;}boolForcedRecompile(JSContext*cx){returnRecompileImpl(cx,/* force = */true);}boolRecompile(JSContext*cx){returnRecompileImpl(cx,/* force = */false);}boolSetDenseOrUnboxedArrayElement(JSContext*cx,HandleObjectobj,int32_tindex,HandleValuevalue,boolstrict){// This function is called from Ion code for StoreElementHole's OOL path.// In this case we know the object is native or an unboxed array and that// no type changes are needed.DenseElementResultresult=SetOrExtendAnyBoxedOrUnboxedDenseElements(cx,obj,index,value.address(),1,ShouldUpdateTypes::DontUpdate);if(result!=DenseElementResult::Incomplete)returnresult==DenseElementResult::Success;RootedValueindexVal(cx,Int32Value(index));returnSetObjectElement(cx,obj,indexVal,value,strict);}voidAutoDetectInvalidation::setReturnOverride(){cx_->setIonReturnOverride(rval_.get());}voidAssertValidObjectPtr(JSContext*cx,JSObject*obj){#ifdef DEBUG// Check what we can, so that we'll hopefully assert/crash if we get a// bogus object (pointer).MOZ_ASSERT(obj->compartment()==cx->compartment());MOZ_ASSERT(obj->runtimeFromActiveCooperatingThread()==cx->runtime());MOZ_ASSERT_IF(!obj->hasLazyGroup()&&obj->maybeShape(),obj->group()->clasp()==obj->maybeShape()->getObjectClass());if(obj->isTenured()){MOZ_ASSERT(obj->isAligned());gc::AllocKindkind=obj->asTenured().getAllocKind();MOZ_ASSERT(gc::IsObjectAllocKind(kind));MOZ_ASSERT(obj->asTenured().zone()==cx->zone());}#endif}voidAssertValidObjectOrNullPtr(JSContext*cx,JSObject*obj){if(obj)AssertValidObjectPtr(cx,obj);}voidAssertValidStringPtr(JSContext*cx,JSString*str){#ifdef DEBUG// We can't closely inspect strings from another runtime.if(str->runtimeFromAnyThread()!=cx->runtime()){MOZ_ASSERT(str->isPermanentAtom());return;}if(str->isAtom())MOZ_ASSERT(str->zone()->isAtomsZone());elseMOZ_ASSERT(str->zone()==cx->zone());MOZ_ASSERT(str->isAligned());MOZ_ASSERT(str->length()<=JSString::MAX_LENGTH);gc::AllocKindkind=str->getAllocKind();if(str->isFatInline()){MOZ_ASSERT(kind==gc::AllocKind::FAT_INLINE_STRING||kind==gc::AllocKind::FAT_INLINE_ATOM);}elseif(str->isExternal()){MOZ_ASSERT(kind==gc::AllocKind::EXTERNAL_STRING);}elseif(str->isAtom()){MOZ_ASSERT(kind==gc::AllocKind::ATOM);}elseif(str->isFlat()){MOZ_ASSERT(kind==gc::AllocKind::STRING||kind==gc::AllocKind::FAT_INLINE_STRING||kind==gc::AllocKind::EXTERNAL_STRING);}else{MOZ_ASSERT(kind==gc::AllocKind::STRING);}#endif}voidAssertValidSymbolPtr(JSContext*cx,JS::Symbol*sym){// We can't closely inspect symbols from another runtime.if(sym->runtimeFromAnyThread()!=cx->runtime()){MOZ_ASSERT(sym->isWellKnownSymbol());return;}MOZ_ASSERT(sym->zone()->isAtomsZone());MOZ_ASSERT(sym->isAligned());if(JSString*desc=sym->description()){MOZ_ASSERT(desc->isAtom());AssertValidStringPtr(cx,desc);}MOZ_ASSERT(sym->getAllocKind()==gc::AllocKind::SYMBOL);}voidAssertValidValue(JSContext*cx,Value*v){if(v->isObject())AssertValidObjectPtr(cx,&v->toObject());elseif(v->isString())AssertValidStringPtr(cx,v->toString());elseif(v->isSymbol())AssertValidSymbolPtr(cx,v->toSymbol());}boolObjectIsCallable(JSObject*obj){returnobj->isCallable();}boolObjectIsConstructor(JSObject*obj){returnobj->isConstructor();}voidMarkValueFromIon(JSRuntime*rt,Value*vp){TraceManuallyBarrieredEdge(&rt->gc.marker,vp,"write barrier");}voidMarkStringFromIon(JSRuntime*rt,JSString**stringp){MOZ_ASSERT(*stringp);TraceManuallyBarrieredEdge(&rt->gc.marker,stringp,"write barrier");}voidMarkObjectFromIon(JSRuntime*rt,JSObject**objp){MOZ_ASSERT(*objp);TraceManuallyBarrieredEdge(&rt->gc.marker,objp,"write barrier");}voidMarkShapeFromIon(JSRuntime*rt,Shape**shapep){TraceManuallyBarrieredEdge(&rt->gc.marker,shapep,"write barrier");}voidMarkObjectGroupFromIon(JSRuntime*rt,ObjectGroup**groupp){TraceManuallyBarrieredEdge(&rt->gc.marker,groupp,"write barrier");}boolThrowRuntimeLexicalError(JSContext*cx,unsignederrorNumber){ScriptFrameIteriter(cx);RootedScriptscript(cx,iter.script());ReportRuntimeLexicalError(cx,errorNumber,script,iter.pc());returnfalse;}boolThrowReadOnlyError(JSContext*cx,HandleObjectobj,int32_tindex){// We have to throw different errors depending on whether |index| is past// the array length, etc. It's simpler to just call SetProperty to ensure// we match the interpreter.RootedValueobjVal(cx,ObjectValue(*obj));RootedValueindexVal(cx,Int32Value(index));RootedIdid(cx);if(!ValueToId<CanGC>(cx,indexVal,&id))returnfalse;ObjectOpResultresult;MOZ_ALWAYS_FALSE(SetProperty(cx,obj,id,UndefinedHandleValue,objVal,result)&&result.checkStrictErrorOrWarning(cx,obj,id,/* strict = */true));returnfalse;}boolThrowBadDerivedReturn(JSContext*cx,HandleValuev){ReportValueError(cx,JSMSG_BAD_DERIVED_RETURN,JSDVG_IGNORE_STACK,v,nullptr);returnfalse;}boolBaselineThrowUninitializedThis(JSContext*cx,BaselineFrame*frame){returnThrowUninitializedThis(cx,frame);}boolBaselineThrowInitializedThis(JSContext*cx,BaselineFrame*frame){returnThrowInitializedThis(cx,frame);}boolThrowObjectCoercible(JSContext*cx,HandleValuev){MOZ_ASSERT(v.isUndefined()||v.isNull());MOZ_ALWAYS_FALSE(ToObjectSlow(cx,v,true));returnfalse;}boolBaselineGetFunctionThis(JSContext*cx,BaselineFrame*frame,MutableHandleValueres){returnGetFunctionThis(cx,frame,res);}boolCallNativeGetter(JSContext*cx,HandleFunctioncallee,HandleObjectobj,MutableHandleValueresult){MOZ_ASSERT(callee->isNative());JSNativenatfun=callee->native();JS::AutoValueArray<2>vp(cx);vp[0].setObject(*callee.get());vp[1].setObject(*obj.get());if(!natfun(cx,0,vp.begin()))returnfalse;result.set(vp[0]);returntrue;}boolCallNativeSetter(JSContext*cx,HandleFunctioncallee,HandleObjectobj,HandleValuerhs){MOZ_ASSERT(callee->isNative());JSNativenatfun=callee->native();JS::AutoValueArray<3>vp(cx);vp[0].setObject(*callee.get());vp[1].setObject(*obj.get());vp[2].set(rhs);returnnatfun(cx,1,vp.begin());}boolEqualStringsHelper(JSString*str1,JSString*str2){// IC code calls this directly so we shouldn't GC.JS::AutoCheckCannotGCnogc;MOZ_ASSERT(str1->isAtom());MOZ_ASSERT(!str2->isAtom());MOZ_ASSERT(str1->length()==str2->length());JSLinearString*str2Linear=str2->ensureLinear(nullptr);if(!str2Linear)returnfalse;returnEqualChars(&str1->asLinear(),str2Linear);}boolCheckIsCallable(JSContext*cx,HandleValuev,CheckIsCallableKindkind){if(!IsCallable(v))returnThrowCheckIsCallable(cx,kind);returntrue;}template<boolHandleMissing>staticMOZ_ALWAYS_INLINEboolGetNativeDataProperty(JSContext*cx,NativeObject*obj,jsidid,Value*vp){// Fast path used by megamorphic IC stubs. Unlike our other property// lookup paths, this is optimized to be as fast as possible for simple// data property lookups.JS::AutoCheckCannotGCnogc;MOZ_ASSERT(JSID_IS_ATOM(id)||JSID_IS_SYMBOL(id));while(true){if(Shape*shape=obj->lastProperty()->search(cx,id)){if(!shape->hasSlot()||!shape->hasDefaultGetter())returnfalse;*vp=obj->getSlot(shape->slot());returntrue;}// Property not found. Watch out for Class hooks.if(MOZ_UNLIKELY(!obj->is<PlainObject>())){if(ClassMayResolveId(cx->names(),obj->getClass(),id,obj)||obj->getClass()->getGetProperty()){returnfalse;}}JSObject*proto=obj->staticPrototype();if(!proto){if(HandleMissing){vp->setUndefined();returntrue;}returnfalse;}if(!proto->isNative())returnfalse;obj=&proto->as<NativeObject>();}}template<boolHandleMissing>boolGetNativeDataProperty(JSContext*cx,JSObject*obj,PropertyName*name,Value*vp){if(MOZ_UNLIKELY(!obj->isNative()))returnfalse;returnGetNativeDataProperty<HandleMissing>(cx,&obj->as<NativeObject>(),NameToId(name),vp);}templateboolGetNativeDataProperty<true>(JSContext*cx,JSObject*obj,PropertyName*name,Value*vp);templateboolGetNativeDataProperty<false>(JSContext*cx,JSObject*obj,PropertyName*name,Value*vp);staticMOZ_ALWAYS_INLINEboolValueToAtomOrSymbol(JSContext*cx,Value&idVal,jsid*id){JS::AutoCheckCannotGCnogc;if(MOZ_LIKELY(idVal.isString())){JSString*s=idVal.toString();JSAtom*atom;if(s->isAtom()){atom=&s->asAtom();}else{atom=AtomizeString(cx,s);if(!atom)returnfalse;}*id=AtomToId(atom);}elseif(idVal.isSymbol()){*id=SYMBOL_TO_JSID(idVal.toSymbol());}else{if(!ValueToIdPure(idVal,id))returnfalse;}// Watch out for ids that may be stored in dense elements.static_assert(NativeObject::MAX_DENSE_ELEMENTS_COUNT<JSID_INT_MAX,"All dense elements must have integer jsids");if(MOZ_UNLIKELY(JSID_IS_INT(*id)))returnfalse;returntrue;}template<boolHandleMissing>boolGetNativeDataPropertyByValue(JSContext*cx,JSObject*obj,Value*vp){JS::AutoCheckCannotGCnogc;if(MOZ_UNLIKELY(!obj->isNative()))returnfalse;// vp[0] contains the id, result will be stored in vp[1].ValueidVal=vp[0];jsidid;if(!ValueToAtomOrSymbol(cx,idVal,&id))returnfalse;Value*res=vp+1;returnGetNativeDataProperty<HandleMissing>(cx,&obj->as<NativeObject>(),id,res);}templateboolGetNativeDataPropertyByValue<true>(JSContext*cx,JSObject*obj,Value*vp);templateboolGetNativeDataPropertyByValue<false>(JSContext*cx,JSObject*obj,Value*vp);template<boolNeedsTypeBarrier>boolSetNativeDataProperty(JSContext*cx,JSObject*obj,PropertyName*name,Value*val){JS::AutoCheckCannotGCnogc;if(MOZ_UNLIKELY(!obj->isNative()))returnfalse;NativeObject*nobj=&obj->as<NativeObject>();Shape*shape=nobj->lastProperty()->search(cx,NameToId(name));if(!shape||!shape->hasSlot()||!shape->hasDefaultSetter()||!shape->writable()||nobj->watched()){returnfalse;}if(NeedsTypeBarrier&&!HasTypePropertyId(nobj,NameToId(name),*val))returnfalse;nobj->setSlot(shape->slot(),*val);returntrue;}templateboolSetNativeDataProperty<true>(JSContext*cx,JSObject*obj,PropertyName*name,Value*val);templateboolSetNativeDataProperty<false>(JSContext*cx,JSObject*obj,PropertyName*name,Value*val);boolObjectHasGetterSetter(JSContext*cx,JSObject*objArg,Shape*propShape){JS::AutoCheckCannotGCnogc;MOZ_ASSERT(propShape->hasGetterObject()||propShape->hasSetterObject());// Window objects may require outerizing (passing the WindowProxy to the// getter/setter), so we don't support them here.if(MOZ_UNLIKELY(!objArg->isNative()||IsWindow(objArg)))returnfalse;NativeObject*nobj=&objArg->as<NativeObject>();jsidid=propShape->propid();while(true){if(Shape*shape=nobj->lastProperty()->search(cx,id)){if(shape==propShape)returntrue;if(shape->getterOrUndefined()==propShape->getterOrUndefined()&&shape->setterOrUndefined()==propShape->setterOrUndefined()){returntrue;}returnfalse;}// Property not found. Watch out for Class hooks.if(!nobj->is<PlainObject>()){if(ClassMayResolveId(cx->names(),nobj->getClass(),id,nobj)||nobj->getClass()->getGetProperty()){returnfalse;}}JSObject*proto=nobj->staticPrototype();if(!proto)returnfalse;if(!proto->isNative())returnfalse;nobj=&proto->as<NativeObject>();}}boolHasOwnNativeDataProperty(JSContext*cx,JSObject*obj,Value*vp){JS::AutoCheckCannotGCnogc;// vp[0] contains the id, result will be stored in vp[1].ValueidVal=vp[0];jsidid;if(!ValueToAtomOrSymbol(cx,idVal,&id))returnfalse;if(!obj->isNative()){if(obj->is<UnboxedPlainObject>()){boolres=obj->as<UnboxedPlainObject>().containsUnboxedOrExpandoProperty(cx,id);vp[1].setBoolean(res);returntrue;}returnfalse;}NativeObject*nobj=&obj->as<NativeObject>();if(nobj->lastProperty()->search(cx,id)){vp[1].setBoolean(true);returntrue;}// Property not found. Watch out for Class hooks.if(MOZ_UNLIKELY(!nobj->is<PlainObject>())){if(ClassMayResolveId(cx->names(),nobj->getClass(),id,nobj))returnfalse;}// Missing property.vp[1].setBoolean(false);returntrue;}JSString*TypeOfObject(JSObject*obj,JSRuntime*rt){JSTypetype=js::TypeOfObject(obj);returnTypeName(type,*rt->commonNames);}}// namespace jit}// namespace js